```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Hibernate-Validator 数据校验框架指南</title>
    <link href="https://cdn.staticfile.org/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
    <link href="https://cdn.staticfile.org/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;500;600;700&family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/mermaid@latest/dist/mermaid.min.js"></script>
    <style>
        body {
            font-family: 'Noto Sans SC', Tahoma, Arial, Roboto, "Droid Sans", "Helvetica Neue", "Droid Sans Fallback", "Heiti SC", "Hiragino Sans GB", Simsun, sans-serif;
            color: #333;
            line-height: 1.6;
        }
        h1, h2, h3 {
            font-family: 'Noto Serif SC', serif;
            font-weight: 600;
        }
        .hero-gradient {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        }
        .code-block {
            background-color: #2d3748;
            border-radius: 0.5rem;
            position: relative;
        }
        .code-copy {
            position: absolute;
            right: 0.5rem;
            top: 0.5rem;
            color: #a0aec0;
            cursor: pointer;
            transition: all 0.2s;
        }
        .code-copy:hover {
            color: white;
        }
        .annotation-card {
            border-left: 4px solid #667eea;
            transition: all 0.3s ease;
        }
        .annotation-card:hover {
            transform: translateY(-2px);
            box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
        }
        .table-container {
            overflow-x: auto;
        }
        .table-annotation {
            border-collapse: separate;
            border-spacing: 0;
            width: 100%;
        }
        .table-annotation th {
            background-color: #4a5568;
            color: white;
            padding: 0.75rem;
            text-align: left;
        }
        .table-annotation td {
            padding: 0.75rem;
            border-bottom: 1px solid #e2e8f0;
        }
        .table-annotation tr:nth-child(even) {
            background-color: #f8fafc;
        }
        .table-annotation tr:hover {
            background-color: #edf2f7;
        }
        .footer {
            background-color: #1a202c;
        }
        .hover-grow {
            transition: all 0.2s ease;
        }
        .hover-grow:hover {
            transform: scale(1.02);
        }
        .highlight-box {
            position: relative;
        }
        .highlight-box::before {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            width: 4px;
            height: 100%;
            background-color: #667eea;
            border-radius: 4px 0 0 4px;
        }
    </style>
</head>
<body class="bg-gray-50">
    <!-- Hero Section -->
    <section class="hero-gradient text-white py-20 px-4 md:px-0">
        <div class="container mx-auto max-w-4xl text-center">
            <h1 class="text-4xl md:text-5xl font-bold mb-6">Hibernate-Validator</h1>
            <p class="text-xl md:text-2xl mb-8 opacity-90">优雅的数据校验解决方案</p>
            <p class="text-lg md:text-xl opacity-80 max-w-3xl mx-auto">
                Hibernate-Validator是Hibernate项目中的一个数据校验框架，能够将数据校验从业务代码中脱离出来，增加代码可读性，同时也让数据校验变得更加方便、简单。
            </p>
            <div class="mt-10">
                <a href="#why-use" class="bg-white text-indigo-700 hover:bg-gray-100 px-6 py-3 rounded-lg font-medium inline-block transition duration-300 transform hover:-translate-y-1 shadow-lg">
                    了解更多 <i class="fas fa-arrow-down ml-2"></i>
                </a>
            </div>
        </div>
    </section>

    <!-- Main Content -->
    <main class="container mx-auto max-w-4xl py-12 px-4">
        <!-- Why Use Section -->
        <section id="why-use" class="mb-16">
            <div class="flex items-center mb-8">
                <div class="w-12 h-12 bg-indigo-100 rounded-full flex items-center justify-center mr-4">
                    <i class="fas fa-question text-indigo-600 text-xl"></i>
                </div>
                <h2 class="text-3xl font-bold text-gray-800">项目中为什么要用校验框架</h2>
            </div>
            <div class="bg-white rounded-xl shadow-md p-6 mb-8 hover-grow">
                <p class="text-gray-700 leading-relaxed">
                    Java程序开发中，当你要处理一个程序的业务逻辑时，请求参数的数据校验是必须要处理的。当请求参数格式不正确的时候，需要程序监测到，并且返回对应的错误提示，以此来达到数据校验的目的。对于前后端分离开发过程中，数据校验还需要返回对应的状态码和错误提示信息。
                </p>
            </div>
            
            <!-- Data Visualization -->
            <div class="bg-white rounded-xl shadow-md p-6 mb-8">
                <div class="mermaid">
                    graph TD
                    A[前端请求] --> B[后端接收参数]
                    B --> C{参数校验}
                    C -->|校验通过| D[执行业务逻辑]
                    C -->|校验失败| E[返回错误信息]
                    E --> F[前端展示错误]
                </div>
            </div>
        </section>

        <!-- Getting Started Section -->
        <section class="mb-16">
            <div class="flex items-center mb-8">
                <div class="w-12 h-12 bg-indigo-100 rounded-full flex items-center justify-center mr-4">
                    <i class="fas fa-rocket text-indigo-600 text-xl"></i>
                </div>
                <h2 class="text-3xl font-bold text-gray-800">快速开始</h2>
            </div>

            <!-- Add Dependency -->
            <div class="mb-12">
                <h3 class="text-2xl font-semibold text-gray-800 mb-4 flex items-center">
                    <i class="fas fa-cubes text-indigo-500 mr-2"></i> 1. 添加依赖
                </h3>
                <div class="code-block text-gray-200 p-4 rounded-lg mb-4">
                    <div class="code-copy" onclick="copyCode(this)">
                        <i class="far fa-copy"></i>
                    </div>
                    <pre class="overflow-x-auto"><code>&lt;dependency&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-starter-validation&lt;/artifactId&gt;
&lt;/dependency&gt;</code></pre>
                </div>
            </div>

            <!-- Add Annotations -->
            <div class="mb-12">
                <h3 class="text-2xl font-semibold text-gray-800 mb-4 flex items-center">
                    <i class="fas fa-tags text-indigo-500 mr-2"></i> 2. 在实体类上添加对应注解
                </h3>
                <div class="code-block text-gray-200 p-4 rounded-lg mb-4">
                    <div class="code-copy" onclick="copyCode(this)">
                        <i class="far fa-copy"></i>
                    </div>
                    <pre class="overflow-x-auto"><code>@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    @NotBlank(message = "用户名不能为空")
    private String name;

    @NotBlank(message = "邮箱不能为空")
    private String email;
}</code></pre>
                </div>
            </div>

            <!-- POST Method -->
            <div class="mb-12">
                <h3 class="text-2xl font-semibold text-gray-800 mb-4 flex items-center">
                    <i class="fas fa-paper-plane text-indigo-500 mr-2"></i> 3. POST方法中应用
                </h3>
                <div class="code-block text-gray-200 p-4 rounded-lg mb-4">
                    <div class="code-copy" onclick="copyCode(this)">
                        <i class="far fa-copy"></i>
                    </div>
                    <pre class="overflow-x-auto"><code>@RestController
public class StudentController {
    @RequestMapping(value = "/addStudent",method = RequestMethod.POST)
    public String addStudent(@Valid @RequestBody Student student){
        System.out.println("student = [" + student + "]");
        return "ok";
    }
}</code></pre>
                </div>
                <div class="annotation-card bg-indigo-50 p-4 rounded-lg mt-2">
                    <p class="text-indigo-800 font-medium"><i class="fas fa-info-circle mr-2"></i> <strong>注意：</strong>POST请求必须要加 <code class="bg-indigo-100 px-2 py-1 rounded">@Valid</code>，表示参数需要校验。</p>
                </div>
            </div>

            <!-- GET Method -->
            <div class="mb-12">
                <h3 class="text-2xl font-semibold text-gray-800 mb-4 flex items-center">
                    <i class="fas fa-download text-indigo-500 mr-2"></i> 4. GET方法中应用
                </h3>
                <div class="code-block text-gray-200 p-4 rounded-lg mb-4">
                    <div class="code-copy" onclick="copyCode(this)">
                        <i class="far fa-copy"></i>
                    </div>
                    <pre class="overflow-x-auto"><code>@RestController
@Validated
public class StudentController {
    @RequestMapping(value = "/addStudent1",method = RequestMethod.GET)
    public String addStudent1(@NotBlank(message = "name不能为空") String name){
        System.out.println("name = [" + name + "]");
        return "ok addStudent1";
    }
}</code></pre>
                </div>
                <div class="annotation-card bg-indigo-50 p-4 rounded-lg mt-2">
                    <p class="text-indigo-800 font-medium"><i class="fas fa-info-circle mr-2"></i> <strong>注意：</strong>Get请求需要在类上添加 <code class="bg-indigo-100 px-2 py-1 rounded">@Validated</code></p>
                </div>
            </div>
        </section>

        <!-- Postman Example -->
        <section class="mb-16">
            <div class="flex items-center mb-8">
                <div class="w-12 h-12 bg-indigo-100 rounded-full flex items-center justify-center mr-4">
                    <i class="fas fa-check-circle text-indigo-600 text-xl"></i>
                </div>
                <h2 class="text-3xl font-bold text-gray-800">Postman测试示例</h2>
            </div>
            <div class="bg-white rounded-xl shadow-md overflow-hidden mb-8 hover-grow">
                <img src="https://cdn.nlark.com/yuque/0/2022/png/21449790/1655381966712-1f9f090a-1229-472a-a479-d9a30c33afd9.png" alt="Postman测试结果" class="w-full h-auto">
            </div>
            <div class="highlight-box bg-white rounded-lg shadow-sm p-6 mb-8">
                <p class="text-gray-700 leading-relaxed">
                    看到这个结果发现我们添加的校验框架起作用了，响应信息中存在了"邮箱不能为空"的信息，但是前端用户一般只关心一个校验结果和校验失败信息，现在返回的这个信息太多了很难让人接受。所以我们需要定义统一的效验失败后返回的格式，这个格式中只包含状态码和失败原因。
                </p>
            </div>
        </section>

        <!-- Elegant Response -->
        <section class="mb-16">
            <div class="flex items-center mb-8">
                <div class="w-12 h-12 bg-indigo-100 rounded-full flex items-center justify-center mr-4">
                    <i class="fas fa-magic text-indigo-600 text-xl"></i>
                </div>
                <h2 class="text-3xl font-bold text-gray-800">定义优雅的返回信息</h2>
            </div>

            <!-- Global Exception Handler -->
            <div class="mb-12">
                <h3 class="text-2xl font-semibold text-gray-800 mb-4 flex items-center">
                    <i class="fas fa-exclamation-triangle text-indigo-500 mr-2"></i> 1. 定义全局异常处理
                </h3>
                <div class="code-block text-gray-200 p-4 rounded-lg mb-4">
                    <div class="code-copy" onclick="copyCode(this)">
                        <i class="far fa-copy"></i>
                    </div>
                    <pre class="overflow-x-auto"><code>@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public ResultEntity handleBindException(MethodArgumentNotValidException ex) {
        FieldError fieldError = ex.getBindingResult().getFieldError();
        // 记录日志。。。
        return ResultEntity.faill(211,fieldError.getDefaultMessage(),null);
    }
}</code></pre>
                </div>
            </div>

            <!-- Response Template -->
            <div class="mb-12">
                <h3 class="text-2xl font-semibold text-gray-800 mb-4 flex items-center">
                    <i class="fas fa-file-alt text-indigo-500 mr-2"></i> 2. 定义校验失败返回模板
                </h3>
                <div class="code-block text-gray-200 p-4 rounded-lg mb-4">
                    <div class="code-copy" onclick="copyCode(this)">
                        <i class="far fa-copy"></i>
                    </div>
                    <pre class="overflow-x-auto"><code>@Data
@AllArgsConstructor
@NoArgsConstructor
public class ResultEntity&lt;T&gt; {
    private Integer code;
    private String message;
    private T data;

    public static &lt;T&gt; ResultEntity&lt;T&gt; faill(Integer code,String msg,T t){
        return new ResultEntity&lt;T&gt;(code,msg,t);
    }
}</code></pre>
                </div>
            </div>

            <!-- Test Result -->
            <div>
                <h3 class="text-2xl font-semibold text-gray-800 mb-4 flex items-center">
                    <i class="fas fa-vial text-indigo-500 mr-2"></i> 3. 测试结果
                </h3>
                <div class="bg-white rounded-xl shadow-md overflow-hidden mb-8 hover-grow">
                    <img src="https://cdn.nlark.com/yuque/0/2022/png/21449790/1655381978984-f595ed55-97e4-4cea-832d-1ede0e33acec.png" alt="优雅的测试结果" class="w-full h-auto">
                </div>
            </div>
        </section>

        <!-- Common Annotations -->
        <section class="mb-16">
            <div class="flex items-center mb-8">
                <div class="w-12 h-12 bg-indigo-100 rounded-full flex items-center justify-center mr-4">
                    <i class="fas fa-list-ul text-indigo-600 text-xl"></i>
                </div>
                <h2 class="text-3xl font-bold text-gray-800">常用注解</h2>
            </div>
            <div class="table-container">
                <table class="table-annotation">
                    <thead>
                        <tr>
                            <th>注解</th>
                            <th>说明</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td>@Null</td>
                            <td>被注释的元素必须为 null</td>
                        </tr>
                        <tr>
                            <td>@NotNull</td>
                            <td>被注释的元素必须不为 null</td>
                        </tr>
                        <tr>
                            <td>@AssertTrue</td>
                            <td>被注释的元素必须为 true</td>
                        </tr>
                        <tr>
                            <td>@AssertFalse</td>
                            <td>被注释的元素必须为 false</td>
                        </tr>
                        <tr>
                            <td>@Min(value)</td>
                            <td>被注释的元素必须是一个数字，其值必须大于等于指定的最小值</td>
                        </tr>
                        <tr>
                            <td>@Max(value)</td>
                            <td>被注释的元素必须是一个数字，其值必须小于等于指定的最大值</td>
                        </tr>
                        <tr>
                            <td>@DecimalMin(value)</td>
                            <td>被注释的元素必须是一个数字，其值必须大于等于指定的最小值</td>
                        </tr>
                        <tr>
                            <td>@DecimalMax(value)</td>
                            <td>被注释的元素必须是一个数字，其值必须小于等于指定的最大值</td>
                        </tr>
                        <tr>
                            <td>@Size(max, min)</td>
                            <td>被注释的元素的大小必须在指定的范围内，元素必须为集合，代表集合个数</td>
                        </tr>
                        <tr>
                            <td>@Pattern(regexp)</td>
                            <td>正则表达式校验</td>
                        </tr>
                        <tr>
                            <td>@Digits(integer, fraction)</td>
                            <td>被注释的元素必须是一个数字，其值必须在可接受的范围内</td>
                        </tr>
                        <tr>
                            <td>@Past</td>
                            <td>被注释的元素必须是一个过去的日期</td>
                        </tr>
                        <tr>
                            <td>@Future</td>
                            <td>被注释的元素必须是一个将来的日期</td>
                        </tr>
                        <tr>
                            <td>@Email</td>
                            <td>被注释的元素必须是电子邮箱地址</td>
                        </tr>
                        <tr>
                            <td>@Length(min=, max=)</td>
                            <td>被注释的字符串的大小必须在指定的范围内，必须为数组或者字符串，若微数组则表示为数组长度，字符串则表示为字符串长度</td>
                        </tr>
                        <tr>
                            <td>@NotEmpty</td>
                            <td>被注释的字符串的必须非空</td>
                        </tr>
                        <tr>
                            <td>@Range(min=, max=)</td>
                            <td>被注释的元素必须在合适的范围内</td>
                        </tr>
                        <tr>
                            <td>@NotBlank</td>
                            <td>被注释的字符串的必须非空</td>
                        </tr>
                        <tr>
                            <td>@URI</td>
                            <td>字符串是否是一个有效的URL</td>
                        </tr>
                    </tbody>
                </table>
            </div>
            <div class="annotation-card bg-yellow-50 p-4 rounded-lg mt-6">
                <p class="text-yellow-800 font-medium"><i class="fas fa-exclamation-triangle mr-2"></i> <strong>注意：</strong></p>
                <ul class="list-disc pl-5 mt-2 text-yellow-800">
                    <li>@NotEmpty 用在集合类上面</li>
                    <li>@NotBlank 用在String上面(包含null和"")</li>
                    <li>@NotNull 用对象上面(只包含null)</li>
                </ul>
            </div>
        </section>

        <!-- Validation Modes -->
        <section class="mb-16">
            <div class="flex items-center mb-8">
                <div class="w-12 h-12 bg-indigo-100 rounded-full flex items-center justify-center mr-4">
                    <i class="fas fa-cogs text-indigo-600 text-xl"></i>
                </div>
                <h2 class="text-3xl font-bold text-gray-800">Hibernate-Validator校验模式</h2>
            </div>

            <div class="grid md:grid-cols-2 gap-8">
                <div class="bg-white rounded-xl shadow-md p-6 hover-grow">
                    <h3 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
                        <i class="fas fa-list-check text-indigo-500 mr-2"></i> 普通模式
                    </h3>
                    <p class="text-gray-700">
                        校验完所有的属性，然后返回所有的验证失败信息，默认是这个模式
                    </p>
                </div>
                <div class="bg-white rounded-xl shadow-md p-6 hover-grow">
                    <h3 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
                        <i class="fas fa-bolt text-indigo-500 mr-2"></i> 快速失败返回模式
                    </h3>
                    <p class="text-gray-700">
                        只要有一个失败就立马返回
                    </p>
                </div>
            </div>

            <!-- Enable Fast Fail -->
            <div class="mt-8">
                <h3 class="text-2xl font-semibold text-gray-800 mb-4 flex items-center">
                    <i class="fas fa-toggle-on text-indigo-500 mr-2"></i> 开启快速失败返回模式
                </h3>
                <div class="code-block text-gray-200 p-4 rounded-lg mb-4">
                    <div class="code-copy" onclick="copyCode(this)">
                        <i class="far fa-copy"></i>
                    </div>
                    <pre class="overflow-x-auto"><code>@Configuration
public class HibernateValidatorConfiguration {
    @Bean
    public Validator validator(){
        ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
                .configure()
                // true  快速失败返回模式    false 普通模式
                .addProperty( "hibernate.validator.fail_fast", "true" )
                .buildValidatorFactory();
        Validator validator = validatorFactory.getValidator();
        return validator;
    }
}</code></pre>
                </div>
                <div class="annotation-card bg-indigo-50 p-4 rounded-lg mt-2">
                    <p class="text-indigo-800 font-medium"><i class="fas fa-info-circle mr-2"></i> 测试验证不通过就会抛出 ConstraintViolationException异常，和之前普通模式下抛出的异常不一样，所以为了格式统一我们还需要自定义的异常处理。</p>
                </div>
            </div>

            <!-- Global Exception Handler for Fast Fail -->
            <div class="mt-8">
                <h3 class="text-2xl font-semibold text-gray-800 mb-4 flex items-center">
                    <i class="fas fa-bug text-indigo-500 mr-2"></i> 全局异常处理
                </h3>
                <div class="code-block text-gray-200 p-4 rounded-lg mb-4">
                    <div class="code-copy" onclick="copyCode(this)">
                        <i class="far fa-copy"></i>
                    </div>
                    <pre class="overflow-x-auto"><code>// 开启快速失败返回模式，GET请求校验不通过会抛出如下异常，在这对它处理
@ExceptionHandler(ConstraintViolationException.class)
@ResponseBody
public ResultEntity handle(ValidationException exception) {
    if (exception instanceof ConstraintViolationException) {
        ConstraintViolationException exs = (ConstraintViolationException) exception;

        Set&lt;ConstraintViolation&lt;?&gt;&gt; violations = exs.getConstraintViolations();
        for (ConstraintViolation&lt;?&gt; item : violations) {
            System.out.println(item.getMessage());
            return ResultEntity.faill(212, item.getMessage(), null);
        }
    }
    return ResultEntity.faill(212, "abc", null);
}</code></pre>
                </div>
            </div>
        </section>

        <!-- Cascading Validation -->
        <section class="mb-16">
            <div class="flex items-center mb-8">
                <div class="w-12 h-12 bg-indigo-100 rounded-full flex items-center justify-center mr-4">
                    <i class="fas fa-project-diagram text-indigo-600 text-xl"></i>
                </div>
                <h2 class="text-3xl font-bold text-gray-800">对象级联校验</h2>
            </div>

            <!-- Student Class -->
            <div class="mb-12">
                <h3 class="text-2xl font-semibold text-gray-800 mb-4 flex items-center">
                    <i class="fas fa-user-graduate text-indigo-500 mr-2"></i> Student 类
                </h3>
                <div class="code-block text-gray-200 p-4 rounded-lg mb-4">
                    <div class="code-copy" onclick="copyCode(this)">
                        <i class="far fa-copy"></i>
                    </div>
                    <pre class="overflow-x-auto"><code>@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    @NotBlank(message = "用户名不能为空")
    private String name;

    @Max(150)
    @Min(10)
    @NotNull(message = "年龄不能为空")
    private Integer age;

    @Email
    private String email;

    @NotNull(message = "user不能为空")
    @Valid
    private User user;
}</code></pre>
                </div>
            </div>

            <!-- User Class -->
            <div>
                <h3 class="text-2xl font-semibold text-gray-800 mb-4 flex items-center">
                    <i class="fas fa-user text-indigo-500 mr-2"></i> User 类
                </h3>
                <div class="code-block text-gray-200 p-4 rounded-lg mb-4">
                    <div class="code-copy" onclick="copyCode(this)">
                        <i class="far fa-copy"></i>
                    </div>
                    <pre class="overflow-x-auto"><code>@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Integer id;

    @NotNull(message = "user对象中的username不能为空")
    private String username;
}</code></pre>
                </div>
            </div>
        </section>
    </main>

    <!-- Footer -->
    <footer class="footer text-white py-8">
        <div class="container mx-auto max-w-4xl px-4">
            <div class="flex flex-col md:flex-row justify-between items-center">
                <div class="mb-4 md:mb-0">
                    <h3 class="text-xl font-semibold">技术小馆</h3>
                </div>
                <div>
                    <a href="http://www.yuque.com/jtostring" class="text-gray-300 hover:text-white transition duration-300">
                        <i class="fas fa-globe mr-2"></i> http://www.yuque.com/jtostring
                    </a>
                </div>
            </div>
        </div>
    </footer>

    <script>
        // Initialize Mermaid
        mermaid.initialize({
            startOnLoad: true,
            theme: 'default',
            flowchart: {
                useMaxWidth: true,
                htmlLabels: true,
                curve: 'basis'
            }
        });

        // Copy code functionality
        function copyCode(element) {
            const codeBlock = element.parentElement.querySelector('pre code');
            const range = document.createRange();
            range.selectNode(codeBlock);
            window.getSelection().removeAllRanges();
            window.getSelection().addRange(range);
            document.execCommand('copy');
            window.getSelection().removeAllRanges();
            
            // Show copied feedback
            const icon = element.querySelector('i');
            icon.classList.remove('fa-copy');
            icon.classList.add('fa-check');
            setTimeout(() => {
                icon.classList.remove('fa-check');
                icon.classList.add('fa-copy');
            }, 2000);
        }
    </script>
</body>
</html>
```